package cn.echo.ecc.service.impl;

import cn.echo.ecc.constants.RedisConstants;
import cn.echo.ecc.domain.Blacklist;
import cn.echo.ecc.domain.MessageSms;
import cn.echo.ecc.dto.RedisSmsDto;
import cn.echo.ecc.dto.SmsCodeDto;
import cn.echo.ecc.enums.GlobalExceptionCode;
import cn.echo.ecc.exception.GlobalCustomException;
import cn.echo.ecc.properties.CommonVerifyConstant;
import cn.echo.ecc.service.IBlacklistService;
import cn.echo.ecc.service.IMessageSmsService;
import cn.echo.ecc.service.IVerifyCodeService;
import cn.echo.ecc.util.AssertUtil;
import cn.echo.ecc.util.StrUtils;
import cn.echo.ecc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private IMessageSmsService messageSmsService;

    @Autowired
    private CommonVerifyConstant commonVerifyConstant;

    @Autowired
    private IBlacklistService blacklistService;

    /**
     * 获取图形验证码
     * @param key
     * @return
     */
    @Override
    public String getImageCode(String key) {
        // 1.使用工具类获取图形验证码
        String code = StrUtils.getComplexRandomString(commonVerifyConstant.getImgcode_length());
        // 2.将图形验证码保存到Redis中
        redisTemplate.opsForValue().set(key, code,commonVerifyConstant.getInterval_time(), TimeUnit.MILLISECONDS);
        // 3.使用工具类将获取的图形验证码编译为base64的字符串
        String verifyCode = VerifyCodeUtils.verifyCode(100, 40, code);
        // 4.返回图形验证码
        return verifyCode;
    }

    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        String imageCode = smsCodeDto.getImageCode();
        String phone = smsCodeDto.getPhone();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        String ip = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRemoteAddr();
        // 1.校验图形验证码是否为空
        AssertUtil.isNotEmpty(imageCode, GlobalExceptionCode.PARAM_IS_NOT_BULL);
        // 2.校验手机号码是否为空，格式是否正确
        AssertUtil.isPhone(phone,GlobalExceptionCode.PHONE_FORMAT_ERROR);
        // 3.校验图形验证码是否过期，是否正确
        String objImageCode = (String)redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isNotEmpty(objImageCode,GlobalExceptionCode.OUT_TIME_CODE_ERROR);
        AssertUtil.isEqualsIgnoreCase(objImageCode,imageCode,GlobalExceptionCode.CODE_ERROR);
        // 4.从Redis中获取手机验证码，判断是否存在
        String phoneCodeKey = String.format(RedisConstants.PHONE_CODE_KEY, phone);
        Object objPhoneCode = redisTemplate.opsForValue().get(phoneCodeKey);
        Date date = new Date();
        String code = "";
        if (objPhoneCode != null) {
            // 4.1存在，获取时间戳，判断时间是否小于倒计时
            RedisSmsDto redisSmsDto = (RedisSmsDto)objPhoneCode;
            Boolean boo = (date.getTime() - redisSmsDto.getTime()) < commonVerifyConstant.getCountdown();
            AssertUtil.isFalse(boo,GlobalExceptionCode.FREQUENT_OPERATION_ERROR);
            // 4.2存在，大于倒计时，沿用手机验证码
            code = redisSmsDto.getCode();
        } else {
            // 4.3不存在，使用工具类生成手机验证码
            code = StrUtils.getRandomString(commonVerifyConstant.getSmscode_length());
        }
        // 5.保存到Redis，刷新过期时间
        RedisSmsDto redisSmsDto = new RedisSmsDto(code, date.getTime());
        redisTemplate.opsForValue().set(phoneCodeKey,redisSmsDto,commonVerifyConstant.getInterval_time(),TimeUnit.MILLISECONDS);
        // 6.校验黑名单
        List<Blacklist> blacklists = blacklistService.getBlacklist();
        AssertUtil.isNotNull(blacklists,GlobalExceptionCode.PARAM_IS_NOT_BULL);
        blacklists.forEach(e -> {
            if (phone.equals(e.getPhone()) || ip.equals(e.getIp())) {
                throw new GlobalCustomException(GlobalExceptionCode.DISABLED_ERROR);
            }
        });
        // 7.发送短信,保存日志信息到t_message_sms表
        sendMessageSms(code,date,phone,ip);
        // 8.短信验证码发送成功后从Redis中删除图形验证码
        redisTemplate.delete(imageCodeKey);
    }

    /**
     * 发送短信,保存日志信息到t_message_sms表
     * @param code
     * @param date
     */
    private void sendMessageSms(String code, Date date,String phone,String ip) {
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(commonVerifyConstant.getTitle());
        messageSms.setSendTime(date);
        String content = String.format(commonVerifyConstant.getContent(), code);
        messageSms.setContent(content);
        messageSms.setIp(ip);
        messageSms.setPhone(phone);
        messageSmsService.insert(messageSms);
        log.info(content);
    }
}
